#nullable enable
using Godot;
using System.Collections.Generic;
using System.Linq;

namespace AndroidUnevenRoadGame.Game
{
	/// <summary>
	/// 负责加载和缓存卡牌数据。
	/// </summary>
	public static class CardDatabase
	{
		private static readonly Dictionary<string, CardDefinition> _cards = new();
		private static bool _isLoaded;

		public static void LoadFromJson(string resourcePath)
		{
			if (_isLoaded)
			{
				return;
			}

			var file = FileAccess.Open(resourcePath, FileAccess.ModeFlags.Read);
			if (file == null)
			{
				GD.PushWarning($"无法打开卡牌配置：{resourcePath}");
				return;
			}

			var jsonText = file.GetAsText();
			file.Dispose();

			var result = Json.ParseString(jsonText);
			if (result.VariantType != Variant.Type.Dictionary)
			{
				GD.PushWarning("卡牌配置格式错误：根节点需要为对象");
				return;
			}

			var rootDict = result.AsGodotDictionary();
			foreach (Variant keyVar in rootDict.Keys)
			{
				var entryVar = rootDict[keyVar];
				if (entryVar.VariantType != Variant.Type.Dictionary)
				{
					GD.PushWarning($"卡牌 {keyVar.AsString()} 解析失败：需要为对象");
					continue;
				}

				var cardDict = entryVar.AsGodotDictionary();
				var parameters = new Dictionary<string, float>();
				string? upgradeToId = null;

				if (cardDict.TryGetValue("parameters", out var parametersVar) &&
					parametersVar.VariantType == Variant.Type.Dictionary)
				{
					var parametersDict = parametersVar.AsGodotDictionary();
					foreach (Variant paramKeyVar in parametersDict.Keys)
					{
						var valueVar = parametersDict[paramKeyVar];
						if (paramKeyVar.VariantType != Variant.Type.String)
						{
							continue;
						}

						if (valueVar.VariantType == Variant.Type.Float)
						{
							parameters[paramKeyVar.AsString()] = (float)valueVar.AsDouble();
						}
						else if (valueVar.VariantType == Variant.Type.Int)
						{
							parameters[paramKeyVar.AsString()] = valueVar.AsInt32();
						}
					}
				}

				if (cardDict.TryGetValue("upgrade_to", out var upgradeVar) &&
					upgradeVar.VariantType == Variant.Type.String)
				{
					upgradeToId = upgradeVar.AsString();
				}

				var fallbackId = keyVar.VariantType == Variant.Type.String ? keyVar.AsString() : "card";
				var id = cardDict.TryGetValue("id", out var idVar) && idVar.VariantType == Variant.Type.String
					? idVar.AsString()
					: fallbackId;

				var definition = new CardDefinition(
					id,
					cardDict.TryGetValue("name", out var nameVar) && nameVar.VariantType == Variant.Type.String ? nameVar.AsString() : fallbackId,
					ParseType(cardDict.TryGetValue("type", out var typeVar) && typeVar.VariantType == Variant.Type.String ? typeVar.AsString() : "Skill"),
					cardDict.TryGetValue("cost", out var costVar) && costVar.VariantType == Variant.Type.Int ? costVar.AsInt32() : 1,
					cardDict.TryGetValue("description", out var descVar) && descVar.VariantType == Variant.Type.String ? descVar.AsString() : string.Empty,
					parameters,
					upgradeToId);

				_cards[definition.Id] = definition;
			}

			_isLoaded = true;
		}

		public static CardDefinition Get(string cardId)
		{
			if (_cards.TryGetValue(cardId, out var card))
			{
				return card;
			}

			GD.PushWarning($"未找到卡牌：{cardId}");
			return new CardDefinition(cardId, cardId, CardType.Skill, 1, string.Empty, new Dictionary<string, float>(), null);
		}

		public static IEnumerable<CardDefinition> GetAll()
		{
			return _cards.Values;
		}

		public static IEnumerable<CardDefinition> GetRandomCards(int count, RandomNumberGenerator rng)
		{
			var list = _cards.Values.ToList();
			if (list.Count == 0 || count <= 0)
			{
				return System.Array.Empty<CardDefinition>();
			}

			var result = new List<CardDefinition>(count);
			while (result.Count < count && list.Count > 0)
			{
				var index = rng.RandiRange(0, list.Count - 1);
				result.Add(list[index]);
				list.RemoveAt(index);
			}

			return result;
		}

		private static CardType ParseType(string type)
		{
			return type switch
			{
				"Attack" => CardType.Attack,
				"Power" => CardType.Power,
				"Status" => CardType.Status,
				"Curse" => CardType.Curse,
				_ => CardType.Skill
			};
		}

		public static bool HasUpgrade(string cardId)
		{
			return _cards.TryGetValue(cardId, out var card) &&
				   !string.IsNullOrEmpty(card.UpgradeToId) &&
				   _cards.ContainsKey(card.UpgradeToId);
		}

		public static bool TryGetUpgrade(string cardId, out CardDefinition upgrade)
		{
			upgrade = null!;
			if (!_cards.TryGetValue(cardId, out var card))
			{
				return false;
			}

			if (string.IsNullOrEmpty(card.UpgradeToId))
			{
				return false;
			}

			if (_cards.TryGetValue(card.UpgradeToId, out var upgraded))
			{
				upgrade = upgraded;
				return true;
			}

			GD.PushWarning($"卡牌 {cardId} 的升级目标 {card.UpgradeToId} 未找到。");
			return false;
		}
	}
}

